package de.mannodermaus.gradle.plugins.junit5.dsl

import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.file.FileSystemLocationProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.reporting.Report.OutputType
import org.gradle.api.tasks.Input
import org.gradle.internal.enterprise.test.FileProperty
import javax.inject.Inject

/**
 * Options for controlling Jacoco reporting
 */
public abstract class JacocoOptions @Inject constructor(
    objects: ObjectFactory
) {

    /**
     * Whether to enable Jacoco task integration
     */
    @get:Input
    public abstract val taskGenerationEnabled: Property<Boolean>

    /**
     * Filter the generated Jacoco tasks,
     * so that only the given build variants are provided with a companion task.
     * Make sure to add the full product flavor name if necessary
     * (i.e. "paidDebug" if you use a "paid" product flavor and the "debug" build type).
     * By default, this set is empty, meaning that tasks are generated for all variants.
     */
    @get:Input
    public abstract val onlyGenerateTasksForVariants: SetProperty<String>

    /**
     * Options for controlling the HTML Report generated by Jacoco
     */
    public val html: DirectoryReport = objects.newInstance(DirectoryReport::class.java)

    /**
     * Options for controlling the CSV Report generated by Jacoco
     */
    public val csv: FileReport = objects.newInstance(FileReport::class.java)

    /**
     * Options for controlling the XML Report generated by Jacoco
     */
    public val xml: FileReport = objects.newInstance(FileReport::class.java)

    /**
     * List of class name patterns that should be excluded from being processed by Jacoco.
     * By default, this will exclude R.class & BuildConfig.class
     */
    @get:Input
    public abstract val excludedClasses: ListProperty<String>

    public sealed class Report {
        /**
         * Whether this report should be generated
         */
        @get:Input
        public abstract val enabled: Property<Boolean>

        /**
         * Name of the file/directory to be generated; note that
         * due to the variant-aware nature of the plugin,
         * each variant will be assigned a distinct folder if necessary
         */
        public abstract val destination: FileSystemLocationProperty<out FileSystemLocation>
    }

    public abstract class DirectoryReport : Report() {
        @get:Input
        public abstract override val destination: DirectoryProperty

        public operator fun invoke(config: DirectoryReport.() -> Unit) {
            this.config()
        }
    }

    public abstract class FileReport : Report() {
        @get:Input
        public abstract override val destination: RegularFileProperty

        public operator fun invoke(config: FileReport.() -> Unit) {
            this.config()
        }
    }
}
